function YearMonth(year, month) {
    if (month <= 0 || month > 12) {
        throw "month should be between [1,12]";
    }

    this._date = new Date(year, month - 1);
}

YearMonth.fromDate = function(date) {
    return new YearMonth(date.getFullYear(), date.getMonth() + 1);
};

YearMonth.prototype = {
    year: function() {
        return this._date.getFullYear();
    },

    month: function() {
        return this._date.getMonth() + 1;
    },

    firstDayOfMonth: function() {
        return this._date.clone();
    },

    lastDayOfMonth: function() {
        return this.addMonths(1)._date.addDays(-1).clone();
    },

    dateRangeOfMonth: function() {
        return new DateRange(this.firstDayOfMonth(), this.lastDayOfMonth().addDays(1).addMilliseconds(-1));
    },

    isCurrentMonth: function() {
        return this.lastDayOfMonth() - new Date() > 0;
    },

    january: function() {
        return new YearMonth(this.year(), 1);
    },

    addMonths: function(count) {
        var date = this._date.clone().addMonths(count);
        return new YearMonth(date.getFullYear(), date.getMonth() + 1);
    },

    addYears: function(count) {
        return new YearMonth(this.year() + count, this.month());
    },

    compare: function(other) {
        var diff = this._date - other._date;
        if (diff == 0) return 0;
        return diff < 0 ? -1 : 1;
    },

    isEarlierThan: function(other) {
        return this.compare(other) < 0;
    },

    isLaterThan: function(other) {
        return this.compare(other) > 0;
    },

    isSameWith: function(other) {
        return this.compare(other) == 0;
    },

    toString: function() {
        return this.year() + "-" + this.month();
    },
    toDate: function() {
        return this._date.clone();
    },
    toDto: function() {
        return { year: this.year(), month: this.month() };
    }
}

Date.prototype.toYearMonth = function() {
    return new YearMonth(this.getFullYear(), this.getMonth() + 1);
}